; *****************************************************************
; FAT12 filesystem / simple driver
; Part of kernel loader (RDKRLD.SYS) - Second Stage Boot Loader
;
; Copyrights 2011 Michal Saman, m.saman@designplus.cz.
; This source code is release under the Apache License 2.0.
; http://www.apache.org/licenses/LICENSE-2.0
; *****************************************************************

bits 16

%include	"boot/floppy.inc"

%define	FAT_SEG			0x2C0			; segment to store FAT
%define	ROOT_SEG		0x47C0			; root directory segment

;*************************************************
; LoadRootFat12()
; Loads Root Directory table to memory at 0x7E00
;*************************************************

LoadRootFat12:
	pusha								; store all registers
	push	es							; store es

	;compute size of root directory in sectors and store in CX
	xor		cx, cx						; clear cx
	xor		dx, dx						; clear dx
	mov		ax, 0x0020					; One entry in root table has 32 bytes
	mul		WORD [bpbRootEntries]		; Multiple count of entries to get total size in bytes
	div		WORD [bpbBytesPerSector]	; Get count of sector of root directory
	xchg	ax, cx						; move into ax

	; compute location of root directory and store in AX
	mov		al, BYTE [bpbNumberOfFATs]		; numbers of FATs (on floppy 2)
	mul		WORD [bpbSectorsPerFAT]			; sectors used by one FAT
	add		ax, WORD [bpbReservedSectors]	; in AX is now location of root directory
	mov		WORD [datasector], ax
	add		WORD [datasector], cx			; now we have position of first data sector (after reserver, FAT and root sectors...)

	; read root directory to memory
	push	word ROOT_SEG					; set memory of read buffer address
	pop		es								; load it in es
	mov		bx, 0							; position where we want to load root directory in memory (offset, complet adress is ROOT_SEG:0 = ES:BX)
	call	readSectors
	pop		es								; restore es
	popa									; restore all registers ...
	ret										; ... and return

;*******************************************
; LoadFAT12()
; Loads FAT to 0x7C00
;*******************************************

LoadFAT12:
	pusha											; save all registers
	push es											; save es (0)

	; compute size of FAT and store in CX
	xor		ax, ax									; clear ax
	mov		al, BYTE [bpbNumberOfFATs]				; number of FATs to al
	mul		WORD [bpbSectorsPerFAT]					; get size of all FATs in sectors and store it in ax
	mov		cx, ax									

	; compute location of FAT and store in AX
	mov		ax, WORD [bpbReservedSectors]			; get count of reserved sectors, because FAT start right after...

	; read FAT into memory (07C00:0)
	push	word FAT_SEG
	pop		es
	mov		bx, 0
	call	readSectors								; read to (ES:BX) == (FAT_SEG:0)
	pop		es										; restore es (0)
	popa											; restore all registers
	ret

;********************************************************
; FindFileFat12()
; Search for file name in ROOT DIRECTORY
; Params:
;	DS:SI - filename
;	return AX - file index number in directory table (-1 if error)
;********************************************************

FindFileFat12:

	push	es
	push	cx
	push	dx
	push	bx
	mov		bx, si

	mov		cx, word [bpbRootEntries]		; load loop counter
	push	word ROOT_SEG
	pop		es
	xor		di, di							; set the start of root directory in memory
	cld										; clear direction flag
	.LOOP:
		push	cx
		mov		cx, 0x000B					; eveleven character name
		mov		si, bx						; imageName is in bx
		push	di
	rep	cmpsb								; test if match with root entry
		pop		di
		je		.Found
		pop		cx
		add		di, 0x0020					; add 32 bytes - go to next entry
		loop	.LOOP

	.NotFound:
		pop	bx
		pop	dx
		pop cx
		pop	es
		mov	ax, -1
		ret

	.Found:
		pop	ax								; restore CX to AX (our result)
		pop	bx
		pop	dx
		pop	cx
		pop	es
		ret

;*************************************************
; LoadFileFat12()
;	Load file from FAT12 fs to memory buffer
; Params:
;	ES:SI - File to load
;	BX:BP - buffer to load file to
;	return AX - -1 on error, 0 on success
;	return CX - number of sectors readed
;**************************************************

LoadFileFat12:
	xor		ecx, ecx					; clear ecx
	push	ecx

	.Find:
		push	bx						; segment (BX = 0x37C0)
		push	bp						; offset  (BP = 0x0)
		call	FindFileFat12
		cmp		ax, -1
		jne		.LoadImagePre
		pop		bp						; file not found, end with -1 code
		pop		bx
		pop		ecx
		mov		ax, -1
		ret

	.LoadImagePre:
		;get starting cluster
		push	word ROOT_SEG
		pop		es
		mov		dx, word [es:di + 26]			; DI points to file entry in root directory. offset +26bytes contains position of first file sector
		mov		word [cluster], dx					; file first cluster
		pop		bx									; restore BP to BX - 0x0
		pop		es									; restore BX to ES (0x37C0), complete location is BX:BP

		push	bx									; save it for later use
		push	es
		call	LoadFAT12							; load FAT and determine position on first cluster

	.LoadImage:
		mov		ax, WORD [cluster]					; position of first cluster (LBA) of file
		;call	PrintRegister16

		pop		es									; (es = 0x37C0)
		pop		bx									; (bx = 0)
		call	clusterToLba						; convert cluster to LBA
		xor		cx, cx
		mov		cl, BYTE [bpbSectorsPerCluster]		; sectors to read

		call	readSectors							; reads to (ES:BX) == (0x37C0:0)
		
		;mov	si, msgOK
		;call	Puts16			
		pop		ecx
		inc		ecx
		push	ecx

		push	bx									; BX = 0
		push	es									; ES = 0x37C0

		mov		ax, FAT_SEG
		mov		es, ax
		xor		ebx, ebx
		
		; compute next cluster
		mov		ax, WORD [cluster]				
		mov		cx, ax						; copy current cluster
		mov		dx, ax						; copy current cluster
		shr		dx, 0x0001					; divide by two
		add		cx, dx						; sum for 3/2
			
		mov		ebx, 0
		add		bx, cx
		
		mov		dx, WORD [es:bx]			; read two bytes from FAT
		test	ax, 0x0001					; sudy nebo lichy?
		jnz		.ODD_CLUSTER
	.EVEN_CLUSTER:
		and		dx, 0000111111111111b	; take low twelve bits
		jmp		.DONE
	.ODD_CLUSTER:
		shr		dx, 0x0004				; take high twelve bits
	.DONE:
		mov		WORD [cluster], dx		; store position of new cluster		
		cmp		dx, 0x0FF0				; test for end of file
		jb		.LoadImage

	.SUCCESS:
		pop	es
		pop	bx
		pop	ecx
		xor	ax, ax
		ret
